指向void的指针
一个指向任何对象类型的指针都可以赋值给类型void*的变量,void*可以赋值给另一个void*,两个void*可以比较相等与否,而且可以显式地将void*转换到另一个类型。其他操作都是不安全的,因为编译器并不知道实际被指的是哪种对象。因此,对void*做其他任何操作都将引起编译错误。要使用void*,我们就必须显式地将它转换到某个指向特定类型的指针。例如,
void f(int* pi)
{
void* pv = pi; // 可以:从int* 到void*的隐式转换式
*pv; // 错误❌:void*不能间接引用
pv++; // 错误❌:void*不能增量(不知道被指对象的大小)
int* pi2 = static_cast<int*>(pv); // 显式转换回int*
double* pd1 = pv; // 错误❌
double* pd2 = pi; // 错误❌
double* pd3 = static_cast<double*>(pv); // 不安全
}
一般来说,如果一个指针被转换(“强制”,cast)到与被指对象的实际类型不同的指针,使用后一个指针就是不安全的。例如,一台机器可能假设每个double被分配了8个字节,如果真是这样的话,那么,若被pi所指的int不是这样分配就会产生奇怪的行为。这种形式的显式类型转换,从本质上说就是不安全的、丑陋的,所以这里所用的记法static_cast,也被设计成极其丑陋的样子。
void*的最重要用途是需要向函数传递一个指针,而又不能对对象的类型做任何假设。还有就是从函数返回一个无类型的对象。要使用这样的对象,必须通过显式的类型转换。
采用void*的函数通常存在于系统中很低的层次里,在那里需要操作某些真实的硬件资源。例如,
void* my_alloc(size_t n); // 从我特定的堆中分配n字节的存储
在系统中较高层次上出现void*应该认为是可疑的,它们就像是设计错误的指示器。在那些为优化而使用的地方,可以将void*隐藏在类型安全的界面之后(13.5节、24.4.2节)。
到函数的指针(7.7节)和到成员的指针(15.5节)都不能赋给void*。
🔚